#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <string>
using namespace std;

//指定共享内存的大小为4096字节,共享内存的大小以4KB为基本单位
#define defaultsize 4096

const char *pathname = "/home/shuju/Linux/linux-time-machine";
int proj_id = 0x66;
// 1.创建共享内存的唯一标识key
key_t GetShmKey()
{
    key_t key = ftok(pathname, proj_id);
    if (key < 0)
    {
        cerr << "ftok error,errno:" << errno << ",error string:" << strerror(errno) << endl;
        exit(1);
    }
    return key;
}

// 生成的key值为10进制,转换为16进制
string ToHex(key_t key)
{
    char buffer[1024];
    snprintf(buffer, sizeof(buffer), "0x%x", key);
    return buffer;
}

// 2.创建共享内存(shmget())(只需要一个进程(服务端)创建即可,另一个进程(客户端)可根据shmid()函数返回值shmid直接获取即可)
// shmget(key,size,IPC_CREAT|IPC_EXCL)确保服务端创建全新的共享内存
// shmget(key,size,IPC_CREAT)使客户端获取服务端所创建的共享内存
// 由于shmget()函数第三个参数传递不同值&&并且创建共享ll内存可能会失败---->单独封装
int CreatShmOrDie(key_t key, size_t size, int flag)
{
    int shmid = shmget(key, size, flag);
    if (shmid < 0)
    {
        cerr << "shmget error,errno:" << errno << ",error string:" << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

//创建共享内存(服务端)
int CreatShm(key_t key,size_t size)
{ 
    //创建共享内存,指定共享内存权限0666:rw-rw-rw-
    return CreatShmOrDie(key,size,IPC_CREAT|IPC_EXCL|0666);
}

// 获取共享内存(客户端)
int GetShm(key_t key,size_t size)
{
    return CreatShmOrDie(key,size,IPC_CREAT);
}

//释放共享内存(服务端)
void DeleteShm(int shmid)
{
    int n=shmctl(shmid,IPC_RMID,nullptr);
    if(n<0)
    {
        cerr<<"shmctl error,errno:"<<errno<<",error string:"<<strerror(errno)<<endl;
    }
    else
    {
       cout<<"shmctl delete shm sucess,shmid:"<<shmid<<endl;
    }
}

//shmctl()----IPC_STAT
void ShmDsStat(int shmid)
{
    struct shmid_ds shmds;
    int n=shmctl(shmid,IPC_STAT,&shmds);
    if(n<0)
    {
        cout<<"shmctl copy error"<<endl;
        return;
    }
    else
    {
        cout<<"shm_segsz:"<<shmds.shm_segsz<<endl;
        cout<<"shm_nattch:"<<shmds.shm_nattch<<endl;
        cout<<"shm_perm_key:"<<ToHex(shmds.shm_perm.__key)<<endl;
    }
}

//shmctl()----IPC_SET
void ShmDsSet(int shmid)
{
    struct shmid_ds shmds;
    shmds.shm_perm.mode=0777;
    shmds.shm_segsz=2*4096;
    int n=shmctl(shmid,IPC_SET,&shmds);
    if(n<0)
    {
        cout<<"shmctl Set error"<<endl;
        return;
    }
    else
    {
        cout<<"shm_segsz:"<<shmds.shm_segsz<<endl;
        cout<<"shm_mode:"<<shmds.shm_perm.mode<<endl;
    }
}

//将共享内存与进程进行关联(构建页表映射关系)(服务端&&客户端)
void* ShmAttach(int shmid)
{
    void* addr=shmat(shmid,nullptr,0);
    if((long long int)addr==-1)
    {
        cout<<"shmat error"<<endl;
        return nullptr;
    }
    return addr;
}

//将共享内存与进程进行去关联(删除页表映射关系)(服务端&&客户端)
void ShmDetach(void* addr)
{
    int n=shmdt(addr);
    if(n<0)
    {
        cout<<"shmdt error"<<endl;
    }
}